﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.SqlClient;
using System.Data;

namespace Acms.DatabaseTest.Helpers
{
    public static class ParameterHelpers
    {
        public static ParamCollection AddInputParam(this ParamCollection collection, SqlDbType type, object value)
        {
            return collection.AddInputParam("@" + collection.Count, type, value);
        }

        public static ParamCollection AddInputParam(this ParamCollection collection, string name, SqlDbType type, object value)
        {
            var param = GetParameter(name, type);
            if(
                (value is Guid && (Guid)value == Guid.Empty) 
                || value == null
                )
            {
                param.Value = DBNull.Value;
            }
            else
            {
                param.Value = value;
            }
            collection.Add(param);
            return collection;
        }

        private static SqlParameter GetParameter(string name, SqlDbType type)
        {
            var param = new SqlParameter();
            param.ParameterName = name;
            param.SqlDbType = type;
            return param;
        }

        public static ParamCollection AddOutputParam(this ParamCollection collection, string name, SqlDbType type)
        {
            var param = GetParameter(name, type);
            param.Direction = ParameterDirection.Output;
            collection.Add(param);
            return collection;
        }

        public static ParamCollection AddReturnParam(this ParamCollection collection, SqlDbType type)
        {
            var param = GetParameter("RetVal", type);
            param.Direction = ParameterDirection.ReturnValue;
            collection.Add(param);
            return collection;
        }

        public static ParamCollection SetSize(this ParamCollection collection, int size)
        {
            collection.Last().Size = size;
            return collection;
        }

        public static ParamCollection SetPrecission(this ParamCollection collection, byte precision)
        {
            collection.Last().Precision = precision;
            return collection;
        }

        public static ParamCollection SetScale(this ParamCollection collection, byte scale)
        {
            collection.Last().Scale = scale;
            return collection;
        }

        public static T GetReturnValue<T>(this ParamCollection collection)
        {
            var p = collection.FirstOrDefault(x => x.Direction == ParameterDirection.ReturnValue);
            if (p != null)
            {
                return GetValue<T>(p);
            }
            else
            {
                throw new ApplicationException("Parameters did not contain a return parameter");
            }
        }

        public static T GetOutputValue<T>(this ParamCollection collection, string name)
        {
            var p = collection[name];
            if (p != null)
            {
                return GetValue<T>(p);
            }
            else
            {
                throw new ApplicationException(string.Format("Parameters did not contain a parameter '{0}'", name));
            }
        }

        private static T GetValue<T>(SqlParameter p)
        {
            if (p == null)
            {
                throw new ArgumentNullException("p");
            }
            else
            {
                var obj = p.Value;
                if (obj is T)
                {
                    return (T)obj;
                }
                else if (obj == DBNull.Value && default(T) == null)
                {
                    return default(T);
                }
                else
                {
                    throw new ApplicationException(string.Format("Sql Returned a '{0}' for '{1}' which cannot be converted to a '{2}'", obj.GetType().FullName, p.ParameterName, typeof(T).FullName ));
                }
            }
        }

    }
}
